<template>
  <video
    class="video-container"
    id="video"
    object-fit="fill"
    :src="src"
    :enable-progress-gesture="false"
    :controls="false"
    :show-center-play-btn="false"
    @progress="onProgress"
    @waiting="onWaiting"
    @error="onVideoError"
    @ended="onVideoEnd"
    @timeupdate="onTimeupdate"
    @loadedmetadata="onLoadMetadata">
    <template v-if="videoModule.isReadyPlay">
      <template v-if="!videoModule.isStart">
        <view class="cover_play-wrapper">
          <image
            @click="handleChangeAudioStatus('start')"
            class="icon"
            src="https://rwstatic.tentons.cn/web/Lesson/images/operation/pause-icon.png">
          </image>
          <text>{{ videoModule.pageView?.totalTime }}</text>
        </view>
      </template>
      <template v-else-if="videoModule.isWaiting">
        <view class="cover_play-wrapper">
          <CommonLoading :show-text="false" type="circle"></CommonLoading>
        </view>
      </template>
      <view class="operation-wrapper">
        <view class="operation" @touchstart="onTouchOperationStart" @touchend="onTouchControlsEnd"></view>
        <template v-if="videoModule.isFullScreen">
          <view
            @touchstart="onTouchControlsStart"
            @touchend="onTouchControlsEnd"
            :class="['top controls', videoModule.showControls && 'show']">
          </view>
        </template>
        <view
          @touchstart="onTouchControlsStart"
          @touchend="onTouchControlsEnd"
          :class="['bottom controls', videoModule.isFullScreen && 'full_screen', videoModule.showControls && 'show']">
          <view style="display: flex;align-items: center">
            <image
              v-show="!videoModule.isPlaying"
              class="play-icon"
              @click="handleChangeAudioStatus('play')"
              src="https://rwstatic.tentons.cn/web/Lesson/images/operation/video-pause-icon.png">
            </image>
            <image
              v-show="videoModule.isPlaying"
              class="play-icon"
              @click="handleChangeAudioStatus('pause')"
              src="https://rwstatic.tentons.cn/web/Lesson/images/operation/video-play-icon.png">
            </image>
          </view>

          <template v-if="videoModule.isFullScreenOver">
            <CustomProgress
              style="flex: 1"
              :max="videoModule.progress.maxvalue"
              @on-touch-click="setPlayProgress"
              @on-touch-move="onTouchProgressMove"
              @on-touch-end="onTouchProgressEnd"
              :current="videoModule.progress.currentValue">
            </CustomProgress>
          </template>

          <template v-else>
            <CustomProgress
              style="flex: 1"
              :max="videoModule.progress.maxvalue"
              @on-touch-click="setPlayProgress"
              @on-touch-move="onTouchProgressMove"
              @on-touch-end="onTouchProgressEnd"
              :current="videoModule.progress.currentValue">
            </CustomProgress>
          </template>

          <view style="display: flex;align-items: center">
            <view class="time">
              <text>{{ videoModule.pageView?.currentTime }}</text>/<text>{{ videoModule.pageView?.totalTime }}</text>
            </view>
            <view @click="handleChangeSpeed" class="speed-select">
              {{ videoModule.pageView!.speedText }}
            </view>
            <image
              v-show="!videoModule.isFullScreen"
              @click.stop="handleChangeScreen('in')"
              @touchend.stop="onTouchControlsEnd"
              class="change-screen"
              src="https://rwstatic.tentons.cn/web/Lesson/images/operation/in-full-screen.png">
            </image>
            <image
              v-show="videoModule.isFullScreen"
              @click.stop="handleChangeScreen('out')"
              @touchend.stop="onTouchControlsEnd"
              class="change-screen"
              src="https://rwstatic.tentons.cn/web/Lesson/images/operation/out-full-screen.png">
            </image>
          </view>
        </view>
      </view>
    </template>
  </video>
</template>

<script setup lang="ts">
  import { onMounted, onUnmounted, reactive, defineProps, getCurrentInstance } from 'vue';
  import { getFormatTime } from "@/utils/util";
  import CustomProgress from "@/components/customProgress.vue";
  import CommonLoading from '@/components/commonLoading.vue';

  /**
   * @param src 视频地址
   */
  const props = defineProps({
    src: {
      type: String,
      default: ''
    }
  });

  /**
   * 视频全局上下文
   */
  let videoContext: UniApp.VideoContext;

  let videoModule = reactive({
    config: {
      controlsTime: 4000 // 控制器消逝时间
    },
    isWaiting: false,// 出现缓冲
    isFullScreen: false,// 是否全屏
    isStart: false, // 是否点击中间巨大按钮
    isReadyPlay: false,// 数据是否加载完毕
    isPlaying: false, // 是不是播放中
    showControls: false,// 显示controls
    timer: null as any,
    isPaused: false,// 是否暂停
    isFullScreenOver: true,// 是否全屏完成
    progress: {
      maxvalue: 0,
      currentValue: 0,
      currentSpeed: 1,
      speedValue: [1, 1.5, 2],
    },
    pageView: {
      currentTime: '00:00',
      totalTime: '00:00',
      speedText: '1.0x',
    }
  });

  const emits = defineEmits(['error', 'ended']);

  onMounted(() => {
    videoContext = uni.createVideoContext('video', getCurrentInstance());
  });

  onUnmounted(() => {
    destroy();
  });

  /**
   * 切换播放速度
   */
  const handleChangeSpeed = () => {
    let index = videoModule.progress.speedValue.findIndex((item: number) => item == videoModule.progress.currentSpeed);
    if (index + 1 >= videoModule.progress.speedValue.length) {
      videoModule.progress.currentSpeed = videoModule.progress.speedValue[0];
    } else {
      videoModule.progress.currentSpeed = videoModule.progress.speedValue[index + 1];
    }
    videoModule.pageView.speedText = videoModule.progress.currentSpeed.toFixed(1) + '×';
    videoContext.playbackRate(videoModule.progress.currentSpeed);
  }

  /**
   * 切换全屏
   * @param type
   */
  const handleChangeScreen = (type: 'in' | 'out') => {
    onTouchOperationStart();
    videoModule.isFullScreen = type == 'in';
    if (videoModule.isFullScreen) {
      videoContext.requestFullScreen();
    } else {
      videoContext.exitFullScreen();
    }
    setTimeout(() => {// 处理全屏切换完成
      videoModule.isFullScreenOver = !videoModule.isFullScreenOver;
    }, 500);
  }

  /**
   * 操作视频播放or暂停
   * @param type
   */
  const handleChangeAudioStatus = (type: 'start' | 'play' | 'pause') => {
    switch (type) {
      case "pause":
        videoModule.isPlaying = false;
        videoContext.pause();
        break;
      case "start":
        videoModule.isStart = true;
      case "play":
        videoModule.isPlaying = true;
        videoContext.play();
        break;
    }
  }

  /**
   * 监听触摸操作小面板
   */
  const onTouchControlsStart = () => {
    clearTimeout(videoModule.timer);
  }

  /**
   * 监听开始触发操作大面板
   */
  const onTouchOperationStart = () => {
    if (videoModule.timer) {
      clearTimeout(videoModule.timer);
      videoModule.timer = null;
      videoModule.showControls = false;
    } else videoModule.showControls = true;
  }

  /**
   * 监听触摸结束触发
   */
  const onTouchControlsEnd = () => {
    if (!videoModule.showControls) return;
    videoModule.timer = setTimeout(() => {
      videoModule.showControls = false;
      clearTimeout(videoModule.timer);
      videoModule.timer = null;
    }, videoModule.config.controlsTime);
  }

  /**
   * 监听数据是否加载完毕
   * @param duration
   */
  const onLoadMetadata = ({ detail: { duration } }: any) => {
    if (videoModule.isReadyPlay) return;
    videoModule.isReadyPlay = true;
    videoModule.progress.maxvalue = duration;
    videoModule.pageView.totalTime = getFormatTime(duration, 'mm-ss');
  }

  /**
   * 监听视频出现缓冲时
   */
  const onWaiting = () => videoModule.isWaiting = true;

  const onProgress = (e) => {
    //console.log(e);
  }

  /**
   * 监听视频进度
   * @param currentTime
   */
  const onTimeupdate = ({ detail: { currentTime } }: any) => {
    if (videoModule.isPaused) return;
    videoModule.isWaiting = false;
    videoModule.progress.currentValue = currentTime;
    videoModule.pageView.currentTime = getFormatTime(currentTime, 'mm-ss');
  }

  /**
   * 监听视频是否结束
   * @param e
   */
  const onVideoEnd = (e: any) => {
    if (e.type != 'ended') return;
    videoModule.pageView.currentTime = videoModule.pageView.totalTime;
    videoModule.isPlaying = false;
    emits('ended', e);
  }

  /**
   * 监听播放出错
   */
  const onVideoError = (e: any) => {
    emits('error', e);
  }

  // 销毁
  const destroy = () => {
    if (videoContext) {
      (videoContext as any).stop();
    }
  }

  // 更改播放进度
  const setPlayProgress = (value: number) => {
    videoContext.seek(value);
    videoModule.progress.currentValue = value;
    videoModule.pageView.currentTime = getFormatTime(value, 'mm-ss');
  }

  /**
   * 监听进度条移动返回数据
   * @param e
   */
  const onTouchProgressMove = (e: any) => {
    videoModule.isPaused = true;
    setPlayProgress(e);
  }

  /**
   * 监听进度条触摸结束
   * @param e
   */
  const onTouchProgressEnd = (e: any) => {
    videoModule.isPaused = false;
    setPlayProgress(e);
  }
</script>

<style scoped lang="scss">
  @mixin fontStyle($size) {
    font-size: #{ $size }rem;
    font-family: xiaolai;
    color: $uni-text-color;
  }

  .video-container {
    border-radius: 1.2rem;
    border: solid 2px $uni-text-color;
    width: 100%;
    height: 100%;

    .cover_play-wrapper {
      @include fontStyle(1.6);
      height: 100%;
      width: 100%;
      position: absolute;
      z-index: 9;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      background-color: rgba(139, 139, 139, .5);

      .icon {
        height: 6rem;
        width: 6rem;
        margin-bottom: 1rem;
      }
    }

    .operation-wrapper {
      height: 100%;
      width: 100%;
      position: relative;
      z-index: 4;

      .operation {
        position: absolute;
        height: 100%;
        width: 100%;
      }
    }

    .controls {
      position: absolute;
      width: 100%;
      height: 4rem;
      line-height: 4rem;
      padding: 0 1.2rem;
      box-sizing: border-box;
      transition: padding .3s;
      display: flex;
      align-items: center;

      &.full_screen {
        padding: 0 4rem;
        height: calc(constant(safe-area-inset-bottom) + 4rem);
        height: calc(env(safe-area-inset-bottom) + 4rem);
        line-height: calc(constant(safe-area-inset-bottom) + 4rem);
        line-height: calc(env(safe-area-inset-bottom) + 4rem);
      }

      &.top {
        top: 0;
        left: 0;
        background: linear-gradient(to bottom, #8B8B8B, transparent);
        transform: translateY(-100%);

        &.show {
          transition: transform .3s;
          transform: translateY(0%);
        }
      }

      &.bottom {
        left: 0;
        bottom: 0;
        background: linear-gradient(to top, #8B8B8B, transparent);
        transform: translateY(100%);

        &.show {
          transition: transform .3s;
          transform: translateY(0%);
        }

        .play-icon {
          height: 2.4rem;
          width: 2.4rem;
        }

        .time {
          @include fontStyle(1);
          color: #ffffff;
          width: 5rem;
        }

        .speed-select {
          @include fontStyle(1);
          height: 1.1rem;
          line-height: 1;
          display: flex;
          align-items: center;
          justify-content: center;
          width: 3.7rem;
          border: 1px solid #ffffff;
          color: #ffffff;
          border-radius: 0.6rem;
          box-sizing: border-box;
          margin-left: 1rem;
        }

        .change-screen {
          height: 2.4rem;
          width: 2.4rem;
          margin-left: .8rem;
        }
      }
    }
  }
</style>